 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  * Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font
  * should be activated and used by other components.
  *******************************************************************************/
 package org.eclipse.ui.dialogs;

 import com.ibm.icu.text.Collator;
 import java.util.ArrayList ;
 import java.util.Arrays ;
 import java.util.Collections ;
 import java.util.Comparator ;

 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceProxy;
 import org.eclipse.core.resources.IResourceProxyVisitor;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.BusyIndicator;
 import org.eclipse.swt.events.KeyAdapter;
 import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableItem;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
 import org.eclipse.ui.internal.ide.StringMatcher;
 import org.eclipse.ui.model.WorkbenchLabelProvider;

 /**
  * Shows a list of resources to the user with a text entry field
  * for a string pattern used to filter the list of resources.
  * <p>
  *
  * @since 2.1
  */
 public class ResourceListSelectionDialog extends SelectionDialog {
     
     private static final String DIALOG_SETTINGS_SECTION = "ResourceListSelectionDialogSettings"; //$NON-NLS-1$

     Text pattern;

     Table resourceNames;

     Table folderNames;

     String patternString;

     IContainer container;

     int typeMask;

     private static Collator collator = Collator.getInstance();

     boolean gatherResourcesDynamically = true;

     StringMatcher stringMatcher;

     UpdateFilterThread updateFilterThread;

     UpdateGatherThread updateGatherThread;

     ResourceDescriptor[] descriptors;

     int descriptorsSize;

     WorkbenchLabelProvider labelProvider = new WorkbenchLabelProvider();
     
     boolean okEnabled = false;

     private boolean showDerived = false;

     private Button showDerivedButton;

     private boolean allowUserToToggleDerived;
     
     static class ResourceDescriptor implements Comparable {
         String label;

         ArrayList resources = new ArrayList ();

         boolean resourcesSorted = true;

         public int compareTo(Object o) {
             return collator.compare(label, ((ResourceDescriptor) o).label);
         }
     }

     class UpdateFilterThread extends Thread {
         boolean stop = false;

         int firstMatch = 0;

         int lastMatch = descriptorsSize - 1;

         public void run() {
             Display display = resourceNames.getDisplay();
             final int itemIndex[] = { 0 };
             final int itemCount[] = { 0 };
             //Keep track of if the widget got disposed
 //so that we can abort if required
 final boolean[] disposed = { false };
             display.syncExec(new Runnable () {
                 public void run() {
                     //Be sure the widget still exists
 if (resourceNames.isDisposed()) {
                         disposed[0] = true;
                         return;
                     }
                     itemCount[0] = resourceNames.getItemCount();
                 }
             });

             if (disposed[0]) {
                 return;
             }

             int last;
             if ((patternString.indexOf('?') == -1)
                     && (patternString.endsWith("*")) && //$NON-NLS-1$
 (patternString.indexOf('*') == patternString.length() - 1)) {
                 // Use a binary search to get first and last match when the pattern
 // string ends with "*" and has no other embedded special characters.
 // For this case, we can be smarter about getting the first and last
 // match since the items are in sorted order.
 firstMatch = getFirstMatch();
                 if (firstMatch == -1) {
                     firstMatch = 0;
                     lastMatch = -1;
                 } else {
                     lastMatch = getLastMatch();
                 }
                 last = lastMatch;
                 for (int i = firstMatch; i <= lastMatch; i++) {
                     if (i % 50 == 0) {
                         try {
                             Thread.sleep(10);
                         } catch (InterruptedException e) {
                             // ignore
 }
                     }
                     if (stop || resourceNames.isDisposed()) {
                         disposed[0] = true;
                         return;
                     }
                     final int index = i;
                     display.syncExec(new Runnable () {
                         public void run() {
                             if (stop || resourceNames.isDisposed()) {
                                 return;
                             }
                             updateItem(index, itemIndex[0], itemCount[0]);
                             itemIndex[0]++;
                         }
                     });
                 }
             } else {
                 last = lastMatch;
                 boolean setFirstMatch = true;
                 for (int i = firstMatch; i <= lastMatch; i++) {
                     if (i % 50 == 0) {
                         try {
                             Thread.sleep(10);
                         } catch (InterruptedException e) {
                             // ignore
 }
                     }
                     if (stop || resourceNames.isDisposed()) {
                         disposed[0] = true;
                         return;
                     }
                     final int index = i;
                     if (match(descriptors[index].label)) {
                         if (setFirstMatch) {
                             setFirstMatch = false;
                             firstMatch = index;
                         }
                         last = index;
                         display.syncExec(new Runnable () {
                             public void run() {
                                 if (stop || resourceNames.isDisposed()) {
                                     return;
                                 }
                                 updateItem(index, itemIndex[0], itemCount[0]);
                                 itemIndex[0]++;
                             }
                         });
                     }
                 }
             }

             if (disposed[0]) {
                 return;
             }

             lastMatch = last;
             display.syncExec(new Runnable () {
                 public void run() {
                     if (resourceNames.isDisposed()) {
                         return;
                     }
                     itemCount[0] = resourceNames.getItemCount();
                     if (itemIndex[0] < itemCount[0]) {
                         resourceNames.setRedraw(false);
                         resourceNames.remove(itemIndex[0], itemCount[0] - 1);
                         resourceNames.setRedraw(true);
                     }
                     // If no resources, remove remaining folder entries
 if (resourceNames.getItemCount() == 0) {
                         folderNames.removeAll();
                         updateOKState(false);
                     }
                 }
             });
         }
     }

     class UpdateGatherThread extends Thread {
         boolean stop = false;

         int lastMatch = -1;

         int firstMatch = 0;

         boolean refilter = false;

         public void run() {
             Display display = resourceNames.getDisplay();
             final int itemIndex[] = { 0 };
             final int itemCount[] = { 0 };
             //Keep track of if the widget got disposed
 //so that we can abort if required
 final boolean[] disposed = { false };
             display.syncExec(new Runnable () {
                 public void run() {
                     //Be sure the widget still exists
 if (resourceNames.isDisposed()) {
                         disposed[0] = true;
                         return;
                     }
                     itemCount[0] = resourceNames.getItemCount();
                 }
             });

             if (disposed[0]) {
                 return;
             }

             if (!refilter) {
                 for (int i = 0; i <= lastMatch; i++) {
                     if (i % 50 == 0) {
                         try {
                             Thread.sleep(10);
                         } catch (InterruptedException e) {
                             // ignore
 }
                     }
                     if (stop || resourceNames.isDisposed()) {
                         disposed[0] = true;
                         return;
                     }
                     final int index = i;
                     display.syncExec(new Runnable () {
                         public void run() {
                             if (stop || resourceNames.isDisposed()) {
                                 return;
                             }
                             updateItem(index, itemIndex[0], itemCount[0]);
                             itemIndex[0]++;
                         }
                     });
                 }
             } else {
                 // we're filtering the previous list
 for (int i = firstMatch; i <= lastMatch; i++) {
                     if (i % 50 == 0) {
                         try {
                             Thread.sleep(10);
                         } catch (InterruptedException e) {
                             // ignore
 }
                     }
                     if (stop || resourceNames.isDisposed()) {
                         disposed[0] = true;
                         return;
                     }
                     final int index = i;
                     if (match(descriptors[index].label)) {
                         display.syncExec(new Runnable () {
                             public void run() {
                                 if (stop || resourceNames.isDisposed()) {
                                     return;
                                 }
                                 updateItem(index, itemIndex[0], itemCount[0]);
                                 itemIndex[0]++;
                             }
                         });
                     }
                 }
             }

             if (disposed[0]) {
                 return;
             }

             display.syncExec(new Runnable () {
                 public void run() {
                     if (resourceNames.isDisposed()) {
                         return;
                     }
                     itemCount[0] = resourceNames.getItemCount();
                     if (itemIndex[0] < itemCount[0]) {
                         resourceNames.setRedraw(false);
                         resourceNames.remove(itemIndex[0], itemCount[0] - 1);
                         resourceNames.setRedraw(true);
                     }
                     // If no resources, remove remaining folder entries
 if (resourceNames.getItemCount() == 0) {
                         folderNames.removeAll();
                         updateOKState(false);
                     }
                 }
             });
         }
     }

     /**
      * Creates a new instance of the class.
      *
      * @param parentShell shell to parent the dialog on
      * @param resources resources to display in the dialog
      */
     public ResourceListSelectionDialog(Shell parentShell, IResource[] resources) {
         super(parentShell);
         setShellStyle(getShellStyle() | SWT.RESIZE);
         gatherResourcesDynamically = false;
         initDescriptors(resources);
     }

     /**
      * Creates a new instance of the class. When this constructor is used to
      * create the dialog, resources will be gathered dynamically as the pattern
      * string is specified. Only resources of the given types that match the
      * pattern string will be listed. To further filter the matching resources,
      * @see #select(IResource)
      *
      * @param parentShell shell to parent the dialog on
      * @param container container to get resources from
      * @param typeMask mask containing IResource types to be considered
      */
     public ResourceListSelectionDialog(Shell parentShell, IContainer container,
             int typeMask) {
         super(parentShell);
         this.container = container;
         this.typeMask = typeMask;
         setShellStyle(getShellStyle() | SWT.RESIZE);
     }

     /**
      * Adjust the pattern string for matching.
      */
     protected String adjustPattern() {
         String text = pattern.getText().trim();
         if (text.endsWith("<")) { //$NON-NLS-1$
 // the < character indicates an exact match search
 return text.substring(0, text.length() - 1);
         }
         if (!text.equals("") && !text.endsWith("*")) { //$NON-NLS-1$ //$NON-NLS-2$
 return text + "*"; //$NON-NLS-1$
 }
         return text;
     }

     /**
      * @see org.eclipse.jface.dialogs.Dialog#cancelPressed()
      */
     protected void cancelPressed() {
         setResult(null);
         super.cancelPressed();
     }

     /**
      * @see org.eclipse.jface.window.Window#close()
      */
     public boolean close() {
         boolean result = super.close();
         labelProvider.dispose();
         return result;
     }

     /**
      * @see org.eclipse.jface.window.Window#create()
      */
     public void create() {
         super.create();
         pattern.setFocus();
         getButton(IDialogConstants.OK_ID).setEnabled(okEnabled);
     }

     /**
      * Creates the contents of this dialog, initializes the
      * listener and the update thread.
      *
      * @param parent parent to create the dialog widgets in
      */
     protected Control createDialogArea(Composite parent) {

         Composite dialogArea = (Composite) super.createDialogArea(parent);
         Label l = new Label(dialogArea, SWT.NONE);
         l.setText(IDEWorkbenchMessages.ResourceSelectionDialog_label);
         GridData data = new GridData(GridData.FILL_HORIZONTAL);
         l.setLayoutData(data);

         pattern = new Text(dialogArea, SWT.SINGLE | SWT.BORDER);
         pattern.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
         l = new Label(dialogArea, SWT.NONE);
         l.setText(IDEWorkbenchMessages.ResourceSelectionDialog_matching);
         data = new GridData(GridData.FILL_HORIZONTAL);
         l.setLayoutData(data);
         resourceNames = new Table(dialogArea, SWT.SINGLE | SWT.BORDER
                 | SWT.V_SCROLL);
         data = new GridData(GridData.FILL_BOTH);
         data.heightHint = 12 * resourceNames.getItemHeight();
         resourceNames.setLayoutData(data);

         l = new Label(dialogArea, SWT.NONE);
         l.setText(IDEWorkbenchMessages.ResourceSelectionDialog_folders);
         data = new GridData(GridData.FILL_HORIZONTAL);
         l.setLayoutData(data);

         folderNames = new Table(dialogArea, SWT.SINGLE | SWT.BORDER
                 | SWT.V_SCROLL | SWT.H_SCROLL);
         data = new GridData(GridData.FILL_BOTH);
         data.widthHint = 300;
         data.heightHint = 4 * folderNames.getItemHeight();
         folderNames.setLayoutData(data);

         if (gatherResourcesDynamically) {
             updateGatherThread = new UpdateGatherThread();
         } else {
             updateFilterThread = new UpdateFilterThread();
         }

         pattern.addKeyListener(new KeyAdapter() {
             public void keyReleased(KeyEvent e) {
                 if (e.keyCode == SWT.ARROW_DOWN) {
                     resourceNames.setFocus();
                 }
             }
         });

         pattern.addModifyListener(new ModifyListener() {
             public void modifyText(ModifyEvent e) {
                 refresh(false);
             }
         });

         resourceNames.addSelectionListener(new SelectionAdapter() {
             public void widgetSelected(SelectionEvent e) {
                 updateFolders((ResourceDescriptor) e.item.getData());
             }

             public void widgetDefaultSelected(SelectionEvent e) {
                 okPressed();
             }
         });

         folderNames.addSelectionListener(new SelectionAdapter() {
             public void widgetDefaultSelected(SelectionEvent e) {
                 okPressed();
             }
         });

         if (getAllowUserToToggleDerived()) {
             showDerivedButton = new Button(dialogArea, SWT.CHECK);
             showDerivedButton.setText(IDEWorkbenchMessages.ResourceSelectionDialog_showDerived);
             showDerivedButton.addSelectionListener(new SelectionAdapter() {
                 public void widgetSelected(SelectionEvent e) {
                     setShowDerived(showDerivedButton.getSelection());
                     refresh(true);
                 }
             });
             showDerivedButton.setSelection(getShowDerived());
         }
             
         applyDialogFont(dialogArea);
         return dialogArea;
     }

     /**
      * Returns whether to include a "Show derived resources" checkbox in the dialog.
      * The default is <code>false</code>.
      *
      * @return <code>true</code> to include the checkbox, <code>false</code> to omit
      * @since 3.1
      */
     public boolean getAllowUserToToggleDerived() {
         return allowUserToToggleDerived;
     }

     /**
      * Sets whether to include a "Show derived resources" checkbox in the dialog.
      *
      * @param allow <code>true</code> to include the checkbox, <code>false</code> to omit
      * @since 3.1
      */
     public void setAllowUserToToggleDerived(boolean allow) {
         allowUserToToggleDerived = allow;
     }
     
     /**
      */
     private void filterResources(boolean force) {
         String oldPattern = force ? null : patternString;
         patternString = adjustPattern();
         if (!force && patternString.equals(oldPattern)) {
             return;
         }

         updateFilterThread.stop = true;
         stringMatcher = new StringMatcher(patternString, true, false);
         UpdateFilterThread oldThread = updateFilterThread;
         updateFilterThread = new UpdateFilterThread();
         if (patternString.equals("")) { //$NON-NLS-1$
 updateFilterThread.firstMatch = 0;
             updateFilterThread.lastMatch = -1;
             updateFilterThread.start();
             return;
         }

         if (oldPattern != null && (oldPattern.length() != 0)
                 && oldPattern.endsWith("*") && patternString.endsWith("*")) { //$NON-NLS-1$ //$NON-NLS-2$
 int matchLength = oldPattern.length() - 1;
             if (patternString.regionMatches(0, oldPattern, 0, matchLength)) {
                 // filter the previous list of items, this is done when the
 // new pattern is a derivative of the old pattern
 updateFilterThread.firstMatch = oldThread.firstMatch;
                 updateFilterThread.lastMatch = oldThread.lastMatch;
                 updateFilterThread.start();
                 return;
             }
         }

         // filter the entire list
 updateFilterThread.firstMatch = 0;
         updateFilterThread.lastMatch = descriptorsSize - 1;
         updateFilterThread.start();
     }

     /**
      * Use a binary search to get the first match for the patternString.
      * This method assumes the patternString does not contain any '?'
      * characters and that it contains only one '*' character at the end
      * of the string.
      */
     private int getFirstMatch() {
         int high = descriptorsSize;
         int low = -1;
         boolean match = false;
         ResourceDescriptor desc = new ResourceDescriptor();
         desc.label = patternString.substring(0, patternString.length() - 1);
         while (high - low > 1) {
             int index = (high + low) / 2;
             String label = descriptors[index].label;
             if (match(label)) {
                 high = index;
                 match = true;
             } else {
                 int compare = descriptors[index].compareTo(desc);
                 if (compare == -1) {
                     low = index;
                 } else {
                     high = index;
                 }
             }
         }
         if (match) {
             return high;
         }
         return -1;
     }

     /**
      */
     private void gatherResources(boolean force) {
         String oldPattern = force ? null : patternString;
         patternString = adjustPattern();
         if (!force && patternString.equals(oldPattern)) {
             return;
         }

         updateGatherThread.stop = true;
         updateGatherThread = new UpdateGatherThread();

         if (patternString.equals("")) { //$NON-NLS-1$
 updateGatherThread.start();
             return;
         }
         stringMatcher = new StringMatcher(patternString, true, false);

         if (oldPattern != null && (oldPattern.length() != 0)
                 && oldPattern.endsWith("*") && patternString.endsWith("*")) { //$NON-NLS-1$ //$NON-NLS-2$
 // see if the new pattern is a derivative of the old pattern
 int matchLength = oldPattern.length() - 1;
             if (patternString.regionMatches(0, oldPattern, 0, matchLength)) {
                 updateGatherThread.refilter = true;
                 updateGatherThread.firstMatch = 0;
                 updateGatherThread.lastMatch = descriptorsSize - 1;
                 updateGatherThread.start();
                 return;
             }
         }

         final ArrayList resources = new ArrayList ();
         BusyIndicator.showWhile(getShell().getDisplay(), new Runnable () {
             public void run() {
                 getMatchingResources(resources);
                 IResource resourcesArray[] = new IResource[resources.size()];
                 resources.toArray(resourcesArray);
                 initDescriptors(resourcesArray);
             }
         });

         updateGatherThread.firstMatch = 0;
         updateGatherThread.lastMatch = descriptorsSize - 1;
         updateGatherThread.start();
     }

     /**
      * Return an image for a resource descriptor.
      *
      * @param desc resource descriptor to return image for
      * @return an image for a resource descriptor.
      */
     private Image getImage(ResourceDescriptor desc) {
         IResource r = (IResource) desc.resources.get(0);
         return labelProvider.getImage(r);
     }

     /**
      * Use a binary search to get the last match for the patternString.
      * This method assumes the patternString does not contain any '?'
      * characters and that it contains only one '*' character at the end
      * of the string.
      */
     private int getLastMatch() {
         int high = descriptorsSize;
         int low = -1;
         boolean match = false;
         ResourceDescriptor desc = new ResourceDescriptor();
         desc.label = patternString.substring(0, patternString.length() - 1);
         while (high - low > 1) {
             int index = (high + low) / 2;
             String label = descriptors[index].label;
             if (match(label)) {
                 low = index;
                 match = true;
             } else {
                 int compare = descriptors[index].compareTo(desc);
                 if (compare == -1) {
                     low = index;
                 } else {
                     high = index;
                 }
             }
         }
         if (match) {
             return low;
         }
         return -1;
     }

     /**
      * Gather the resources of the specified type that match the current
      * pattern string. Gather the resources using the proxy visitor since
      * this is quicker than getting the entire resource.
      *
      * @param resources resources that match
      */
     private void getMatchingResources(final ArrayList resources) {
         try {
             container.accept(new IResourceProxyVisitor() {
                 public boolean visit(IResourceProxy proxy) {
                     // optionally exclude derived resources (bugs 38085 and 81333)
 if (!getShowDerived() && proxy.isDerived()) {
                         return false;
                     }
                     int type = proxy.getType();
                     if ((typeMask & type) != 0) {
                         if (match(proxy.getName())) {
                             IResource res = proxy.requestResource();
                             if (select(res)) {
                                 resources.add(res);
                                 return true;
                             }
                             return false;
                         }
                     }
                     if (type == IResource.FILE) {
                         return false;
                     }
                     return true;
                 }
             }, IResource.NONE);
         } catch (CoreException e) {
             // ignore
 }
     }

     private Image getParentImage(IResource resource) {
         IResource parent = resource.getParent();
         return labelProvider.getImage(parent);
     }

     private String getParentLabel(IResource resource) {
         IResource parent = resource.getParent();
         String text;
         if (parent.getType() == IResource.ROOT) {
             // Get readable name for workspace root ("Workspace"), without duplicating language-specific string here.
 text = labelProvider.getText(parent);
         } else {
             text = parent.getFullPath().makeRelative().toString();
         }
         if(text == null) {
             return ""; //$NON-NLS-1$
 }
         return text;
     }

     /**
      * Returns whether derived resources should be shown in the list.
      * The default is <code>false</code>.
      *
      * @return <code>true</code> to show derived resources, <code>false</code> to hide them
      * @since 3.1
      */
     protected boolean getShowDerived() {
        return showDerived ;
     }

     /**
      * Sets whether derived resources should be shown in the list.
      *
      * @param show <code>true</code> to show derived resources, <code>false</code> to hide them
      * @since 3.1
      */
     protected void setShowDerived(boolean show) {
         showDerived = show;
     }

     /**
      * Creates a ResourceDescriptor for each IResource,
      * sorts them and removes the duplicated ones.
      *
      * @param resources resources to create resource descriptors for
      */
     private void initDescriptors(final IResource resources[]) {
         BusyIndicator.showWhile(null, new Runnable () {
             public void run() {
                 descriptors = new ResourceDescriptor[resources.length];
                 for (int i = 0; i < resources.length; i++) {
                     IResource r = resources[i];
                     ResourceDescriptor d = new ResourceDescriptor();
                     //TDB: Should use the label provider and compare performance.
 d.label = r.getName();
                     d.resources.add(r);
                     descriptors[i] = d;
                 }
                 Arrays.sort(descriptors);
                 descriptorsSize = descriptors.length;

                 //Merge the resource descriptor with the same label and type.
 int index = 0;
                 if (descriptorsSize < 2) {
                     return;
                 }
                 ResourceDescriptor current = descriptors[index];
                 IResource currentResource = (IResource) current.resources
                         .get(0);
                 for (int i = 1; i < descriptorsSize; i++) {
                     ResourceDescriptor next = descriptors[i];
                     IResource nextResource = (IResource) next.resources.get(0);
                     if (nextResource.getType() == currentResource.getType()
                             && next.label.equals(current.label)) {
                         current.resources.add(nextResource);
                         // If we are merging resources with the same name, into a single descriptor,
 // then we must mark the descriptor unsorted so that we will sort the folder
 // names.
 // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=76496
 current.resourcesSorted = false;
                     } else {
                         if (current.resources.size() > 1) {
                             current.resourcesSorted = false;
                         }
                         descriptors[index + 1] = descriptors[i];
                         index++;
                         current = descriptors[index];
                         currentResource = (IResource) current.resources.get(0);
                     }
                 }
                 descriptorsSize = index + 1;
             }
         });
     }

     /**
      * Returns true if the label matches the chosen pattern.
      *
      * @param label label to match with the current pattern
      * @return true if the label matches the chosen pattern.
      * false otherwise.
      */
     private boolean match(String label) {
         if ((patternString == null)
                 || (patternString.equals("")) || (patternString.equals("*"))) { //$NON-NLS-1$ //$NON-NLS-2$
 return true;
         }
         return stringMatcher.match(label);
     }

     /**
      * The user has selected a resource and the dialog is closing.
      * Set the selected resource as the dialog result.
      */
     protected void okPressed() {
         TableItem items[] = folderNames.getSelection();
         if (items.length == 1) {
             ArrayList result = new ArrayList ();
             result.add(items[0].getData());
             setResult(result);
         }
         super.okPressed();
     }

     /**
      * Use this method to further filter resources. As resources are gathered,
      * if a resource matches the current pattern string, this method will be called.
      * If this method answers false, the resource will not be included in the list
      * of matches and the resource's children will NOT be considered for matching.
      */
     protected boolean select(IResource resource) {
         return true;
     }

     /**
      * Refreshes the filtered list of resources.
      * Called when the text in the pattern text entry has changed.
      *
      * @param force if <code>true</code> a refresh is forced, if <code>false</code> a refresh only
      * occurs if the pattern has changed
      *
      * @since 3.1
      */
     protected void refresh(boolean force) {
         if (gatherResourcesDynamically) {
             gatherResources(force);
         } else {
             filterResources(force);
         }
     }

     /**
      * A new resource has been selected. Change the contents
      * of the folder names list.
      *
      * @desc resource descriptor of the selected resource
      */
     private void updateFolders(final ResourceDescriptor desc) {
         BusyIndicator.showWhile(getShell().getDisplay(), new Runnable () {
             public void run() {
                 if (!desc.resourcesSorted) {
                     // sort the folder names
 Collections.sort(desc.resources, new Comparator () {
                         public int compare(Object o1, Object o2) {
                             String s1 = getParentLabel((IResource) o1);
                             String s2 = getParentLabel((IResource) o2);
                             return collator.compare(s1, s2);
                         }
                     });
                     desc.resourcesSorted = true;
                 }
                 folderNames.removeAll();
                 for (int i = 0; i < desc.resources.size(); i++) {
                     TableItem newItem = new TableItem(folderNames, SWT.NONE);
                     IResource r = (IResource) desc.resources.get(i);
                     newItem.setText(getParentLabel(r));
                     newItem.setImage(getParentImage(r));
                     newItem.setData(r);
                 }
                 folderNames.setSelection(0);
             }
         });
     }

     /**
      * Update the specified item with the new info from the resource
      * descriptor.
      * Create a new table item if there is no item.
      *
      * @param index index of the resource descriptor
      * @param itemPos position of the existing item to update
      * @param itemCount number of items in the resources table widget
      */
     private void updateItem(int index, int itemPos, int itemCount) {
         ResourceDescriptor desc = descriptors[index];
         TableItem item;
         if (itemPos < itemCount) {
             item = resourceNames.getItem(itemPos);
             if (item.getData() != desc) {
                 item.setText(desc.label);
                 item.setData(desc);
                 item.setImage(getImage(desc));
                 if (itemPos == 0) {
                     resourceNames.setSelection(0);
                     updateFolders(desc);
                 }
             }
         } else {
             item = new TableItem(resourceNames, SWT.NONE);
             item.setText(desc.label);
             item.setData(desc);
             item.setImage(getImage(desc));
             if (itemPos == 0) {
                 resourceNames.setSelection(0);
                 updateFolders(desc);
             }
         }
         updateOKState(true);
     }
     
     /**
      * Update the enabled state of the OK button. To be called when
      * the resource list is updated.
      * @param state the new enabled state of the button
      */
     protected void updateOKState(boolean state) {
         Button okButton = getButton(IDialogConstants.OK_ID);
         if(okButton != null && !okButton.isDisposed() && state != okEnabled) {
             okButton.setEnabled(state);
             okEnabled = state;
         }
     }
     
     
     /* (non-Javadoc)
      * @see org.eclipse.jface.window.Dialog#getDialogBoundsSettings()
      *
      * @since 3.2
      */
     protected IDialogSettings getDialogBoundsSettings() {
         IDialogSettings settings = IDEWorkbenchPlugin.getDefault().getDialogSettings();
         IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION);
         if (section == null) {
             section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
         }
         return section;
     }
 }
     

